/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <flgrCoreData.h>
#include <flgrCoreSlideWindow.h>
#include <flgrCoreNhbManage.h>
#include <flgrCoreCopy.h>
#include <flgrCoreDispatch.h>
#include <flgrArith.h>

#include "flgrMorphoKerOp.h"
#include "flgrMorphoBase.h"
#include "flgrMorphoBaseFast.h"
#include "flgrMorphoBaseSegment.h"



/*!
 * \defgroup group_fulguro_morpho Mathematical Morphology
 * \defgroup group_fulguro_core_morpho_base Basic operations
 * \ingroup group_fulguro_morpho
 * \brief Basic Mathematical Morphology Operations
 * @{
 */







void flgr1d_minkowski_sub_fgBIT(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgBIT);
}
void flgr1d_minkowski_sub_fgUINT8(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgUINT8);
}
void flgr1d_minkowski_sub_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgUINT16);
}
void flgr1d_minkowski_sub_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgUINT32);
}
void flgr1d_minkowski_sub_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgINT8);
}
void flgr1d_minkowski_sub_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgINT16);
}
void flgr1d_minkowski_sub_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgINT32);
}
void flgr1d_minkowski_sub_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgFLOAT32);
}
void flgr1d_minkowski_sub_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_minimum_fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Minkoswki substraction of a signal and a 1d shape described as neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the 1D Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_minkowski_sub(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;
  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr1d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_minkowski_sub,datdest,datsrc,nhb);

}



void flgr1d_minkowski_add_fgBIT(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgBIT);
}
void flgr1d_minkowski_add_fgUINT8(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgUINT8);
}
void flgr1d_minkowski_add_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgUINT16);
}
void flgr1d_minkowski_add_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgUINT32);
}
void flgr1d_minkowski_add_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgINT8);
}
void flgr1d_minkowski_add_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgINT16);
}
void flgr1d_minkowski_add_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgINT32);
}
void flgr1d_minkowski_add_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgFLOAT32);
}
void flgr1d_minkowski_add_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr1d_get_nhb_maximum_fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Minkoswki addstraction of a signal and a 1d shape described as neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the 1D Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_minkowski_add(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr1d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_minkowski_add,datdest,datsrc,nhb);

}


void flgr1d_erode_fgBIT(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgBIT);
}
void flgr1d_erode_fgUINT8(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT8);
}
void flgr1d_erode_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT16);
}
void flgr1d_erode_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT32);
}
void flgr1d_erode_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT8);
}
void flgr1d_erode_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT16);
}
void flgr1d_erode_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT32);
}
void flgr1d_erode_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgFLOAT32);
}
void flgr1d_erode_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Erosion of a signal with a neighborhood definition described as a 1d shape
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the 1D Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_erode(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr1d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_erode,datdest,datsrc,nhb);

}



void flgr1d_dilate_fgBIT(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgBIT);
}
void flgr1d_dilate_fgUINT8(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT8);
}
void flgr1d_dilate_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT16);
}
void flgr1d_dilate_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgUINT32);
}
void flgr1d_dilate_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT8);
}
void flgr1d_dilate_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT16);
}
void flgr1d_dilate_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgINT32);
}
void flgr1d_dilate_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgFLOAT32);
}
void flgr1d_dilate_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_maximum_fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Dilation of a signal with a neighborhood definition described as a 1d shape
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the 1D Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_dilate(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr1d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_dilate,datdest,datsrc,nhb);

}


void flgr1d_median_fgBIT(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  flgr_no_define_type_function(FLGR_BIT);
}
void flgr1d_median_fgUINT8(FLGR_Data1D* datdest, FLGR_Data1D* datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgUINT8);
}
void flgr1d_median_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgUINT16);
}
void flgr1d_median_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgUINT32);
}
void flgr1d_median_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgINT8);
}
void flgr1d_median_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgINT16);
}
void flgr1d_median_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgINT32);
}
void flgr1d_median_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgFLOAT32);
}
void flgr1d_median_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr1d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr1d_get_nhb_median_fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Compute median of a signal and a 1d shape described as neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the 1D Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_median(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr1d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_median,datdest,datsrc,nhb);

}


////////////////////////////////////////////////////////////////////////////
/*! Compute Inner Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_gradient_inner(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Data1D *dattmp;
  FLGR_Ret val;


  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp = flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr1d_erode(dattmp, datsrc, nhb))!=0) return val;
  if((val=flgr1d_arith_sub(datdest,datsrc,dattmp))!=0) return val;

  flgr1d_destroy(dattmp);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Outer Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_gradient_outer(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Data1D *dattmp;
  FLGR_Ret val;


  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp=flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr1d_dilate(dattmp, datsrc, nhb))!=0) return val;
  if((val=flgr1d_arith_sub(datdest,dattmp,datsrc))!=0) return val;

  flgr1d_destroy(dattmp);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Thick Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_gradient_thick(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Data1D *dattmpE,*dattmpD;
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmpE = flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  dattmpD = flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  if(dattmpE==NULL) return FLGR_RET_ALLOCATION_ERROR;
  if(dattmpD==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr1d_erode(dattmpE, datsrc, nhb))!=0) return val;
  if((val=flgr1d_dilate(dattmpD, datsrc, nhb))!=0) return val;
  if((val=flgr1d_arith_sub(datdest,dattmpD,dattmpE))!=0) return val;

  flgr1d_destroy(dattmpE);
  flgr1d_destroy(dattmpD);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Openning using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_open(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Data1D *dattmp;
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp = flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr1d_erode(dattmp, datsrc, nhb))!=0) {
    flgr1d_destroy(dattmp);
    return val;
  }

  val=flgr1d_minkowski_add(datdest,dattmp,nhb);

  flgr1d_destroy(dattmp);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Closing using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_close(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Data1D *dattmp;
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp = flgr1d_create_signal(datsrc->length, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr1d_dilate(dattmp, datsrc, nhb))!=0) {
    flgr1d_destroy(dattmp);
    return val;
  }

  val=flgr1d_minkowski_sub(datdest,dattmp,nhb);

  flgr1d_destroy(dattmp);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Tophat by Openning using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_open_tophat(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((val=flgr1d_open(datdest, datsrc, nhb))!=0) return val;

  val=flgr1d_arith_sub(datdest,datsrc,datdest);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Tophat by Closing using a specific neighborhood definition
 *  @param *datdest : pointer to the signal
 *  @param *datsrc : pointer to the signal
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_close_tophat(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, FLGR_Data1D *nhb) {
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((val=flgr1d_close(datdest,datsrc,nhb))!=0) return val;

  val=flgr1d_arith_sub(datdest,datdest,datsrc);

  return val;
}






void flgr2d_minkowski_sub_fgBIT(FLGR_Data2D* datdest, FLGR_Data2D* datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:     
    flgr2d_erode_square_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:      
    flgr2d_erode_cross_fgBIT(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:    
    flgr2d_erode_hexa_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:    
    flgr2d_erode_octagon_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:    
    flgr2d_erode_cross_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgBIT);
  }
}

void flgr2d_minkowski_sub_fgUINT8(FLGR_Data2D* datdest, FLGR_Data2D* datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:     
    flgr2d_erode_square_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:      
    flgr2d_erode_cross_fgUINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:    
    flgr2d_erode_hexa_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:  
    flgr2d_erode_rectangle_fgUINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:    
    flgr2d_erode_octagon_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:    
    flgr2d_erode_cross_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgUINT8);
  }

}

void flgr2d_minkowski_sub_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgUINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgUINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgUINT16);
  }

}
void flgr2d_minkowski_sub_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgUINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgUINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgUINT32);
  }

}
void flgr2d_minkowski_sub_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgINT8);
  }

}
void flgr2d_minkowski_sub_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgINT16);
  }

}
void flgr2d_minkowski_sub_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgINT32);
  }

}
void flgr2d_minkowski_sub_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgFLOAT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgFLOAT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgFLOAT32);
  }

}
void flgr2d_minkowski_sub_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgFLOAT64(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgFLOAT64(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_minimum_fgFLOAT64);
  }

}


////////////////////////////////////////////////////////////////////////////
/*! Minkoswki substraction of an image and a shape described as neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_minkowski_sub(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }

  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_minkowski_sub,datdest,datsrc,nhb);

}

















void flgr2d_minkowski_add_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:     
    flgr2d_dilate_square_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:      
    flgr2d_dilate_cross_fgBIT(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:    
    flgr2d_dilate_hexa_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:    
    flgr2d_dilate_octagon_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:    
    flgr2d_dilate_cross_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgBIT);
  }
}
void flgr2d_minkowski_add_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgUINT8);
  }

}
void flgr2d_minkowski_add_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgUINT16);
  }

}
void flgr2d_minkowski_add_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgUINT32);
  }

}
void flgr2d_minkowski_add_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgINT8);
  }

}
void flgr2d_minkowski_add_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgINT16);
  }

}
void flgr2d_minkowski_add_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgINT32);
  }

}
void flgr2d_minkowski_add_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgFLOAT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgFLOAT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgFLOAT32);
  }

}
void flgr2d_minkowski_add_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgFLOAT64(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgFLOAT64(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_SYM, flgr2d_get_nhb_maximum_fgFLOAT64);
  }

}


////////////////////////////////////////////////////////////////////////////
/*! Minkoswki addition of an image and a shape described as neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_minkowski_add(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_minkowski_add,datdest,datsrc,nhb);

}












void flgr2d_erode_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:     
    flgr2d_erode_square_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:      
    flgr2d_erode_cross_fgBIT(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:    
    flgr2d_erode_hexa_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:    
    flgr2d_erode_octagon_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:    
    flgr2d_erode_cross_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgBIT);
  }  

}
void flgr2d_erode_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgUINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgUINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgUINT8);
  }

}
void flgr2d_erode_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgUINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgUINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgUINT16);
  }

}
void flgr2d_erode_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgUINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgUINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgUINT32);
  }

}
void flgr2d_erode_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgINT8);
  }

}
void flgr2d_erode_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgINT16);
  }

}
void flgr2d_erode_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgINT32);
  }

}
void flgr2d_erode_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgFLOAT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgFLOAT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgFLOAT32);
  }

}
void flgr2d_erode_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_erode_square_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_erode_cross_fgFLOAT64(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_erode_hexa_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_erode_rectangle_fgFLOAT64(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_erode_octagon_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_erode_cross_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_minimum_fgFLOAT64);
  }

}


////////////////////////////////////////////////////////////////////////////
/*! Erode an image using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_erode(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_erode,datdest,datsrc,nhb);

}



















void flgr2d_dilate_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:     
    flgr2d_dilate_square_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:      
    flgr2d_dilate_cross_fgBIT(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:    
    flgr2d_dilate_octagon_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:    
    flgr2d_dilate_cross_fgBIT(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgBIT(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgBIT);
  }  
}
void flgr2d_dilate_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgUINT8);
  }
}
void flgr2d_dilate_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgUINT16);
  }
}
void flgr2d_dilate_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgUINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgUINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgUINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgUINT32);
  }
}
void flgr2d_dilate_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT8(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT8(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT8(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgINT8);
  }
}
void flgr2d_dilate_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT16(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT16(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT16(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgINT16);
  }
}
void flgr2d_dilate_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgINT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgINT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgINT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgINT32);
  }
}
void flgr2d_dilate_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgFLOAT32(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgFLOAT32(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgFLOAT32(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgFLOAT32);
  }
}
void flgr2d_dilate_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;

  FLGR_DECLARE_FUNCTION;

  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    flgr2d_dilate_square_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_CROSS:
    flgr2d_dilate_cross_fgFLOAT64(datdest,datsrc,1);
    break;
  case FLGR_MORPHO_OPTIM_HEXAGON:
    flgr2d_dilate_hexa_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_RECTANGLE:
    flgr2d_dilate_rectangle_fgFLOAT64(datdest,datsrc,nhb->size_x,nhb->size_y);
    break;
  case FLGR_MORPHO_OPTIM_OCTAGON:
    flgr2d_dilate_octagon_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  case FLGR_MORPHO_OPTIM_DIAMOND:
    flgr2d_dilate_cross_fgFLOAT64(datdest,datsrc,nhb->size_x/2);
    break;
  default:
    flgr2d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_maximum_fgFLOAT64);
  }
}


////////////////////////////////////////////////////////////////////////////
/*! Dilate an image using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_dilate(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_dilate,datdest,datsrc,nhb);

}


















void flgr2d_median_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  flgr_no_define_type_function(FLGR_BIT);
}
void flgr2d_median_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  if(nhb->shape == FLGR_RECT) {
    if(nhb->connexity == FLGR_8_CONNEX) {
      if(nhb->size_x == nhb->size_y) {
	if(nhb->size_x == 3) {
	  flgr2d_median_8_connexity_fgUINT8(datdest,datsrc);
	  return;
	}
      }
    }
  }

  flgr2d_raster_slide_window_fgUINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgUINT8);
}
void flgr2d_median_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgUINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgUINT16);
}
void flgr2d_median_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgUINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgUINT32);
}
void flgr2d_median_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgINT8(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgINT8);
}
void flgr2d_median_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgINT16(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgINT16);
}
void flgr2d_median_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgINT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgINT32);
}
void flgr2d_median_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgFLOAT32(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgFLOAT32);
}
void flgr2d_median_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_DECLARE_FUNCTION;
  flgr2d_raster_slide_window_fgFLOAT64(datdest, datsrc, nhb, FLGR_NHB_NO_SYM, flgr2d_get_nhb_median_fgFLOAT64);
}



////////////////////////////////////////////////////////////////////////////
/*! Compute median using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_median(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;


  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_median,datdest,datsrc,nhb);

}











////////////////////////////////////////////////////////////////////////////
/*! Compute Inner Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_gradient_inner(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((val=flgr2d_erode(datdest, datsrc, nhb))!=0) return val;
  if((val=flgr2d_arith_sub(datdest,datsrc,datdest))!=0) return val;

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Outer Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_gradient_outer(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((val=flgr2d_dilate(datdest, datsrc, nhb))!=0) return val;
  if((val=flgr2d_arith_sub(datdest,datdest,datsrc))!=0) return val;

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Thick Morphological Gradient using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_gradient_thick(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Data2D *dattmpD;
  FLGR_Ret val;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmpD = flgr2d_create_pixmap(datsrc->size_y, datsrc->size_x, datdest->spp, datsrc->type);
  if(dattmpD==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((val=flgr2d_erode(datdest, datsrc, nhb))!=0) return val;
  if((val=flgr2d_dilate(dattmpD, datsrc, nhb))!=0) return val;
  if((val=flgr2d_arith_sub(datdest,dattmpD,datdest))!=0) return val;

  flgr2d_destroy(dattmpD);

  return val;
}

////////////////////////////////////////////////////////////////////////////
/*! Openning using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;
  FLGR_Data2D *dattmp;
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }


  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    return flgr2d_open_square(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_HEXAGON:
    return flgr2d_open_hexa(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_RECTANGLE:
    if(nhb->type != FLGR_BIT)
      return flgr2d_open_rectangle(datdest,datsrc,nhb->size_x,nhb->size_y);
    else
      return flgr2d_open_square(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_OCTAGON:
    return flgr2d_open_octagon(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_DIAMOND:
    return flgr2d_open_cross(datdest,datsrc,nhb->size_x/2);

  default:
    break;
  }
  

  dattmp = flgr2d_create_pixmap(datsrc->size_y, datsrc->size_x, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_erode(dattmp, datsrc, nhb))!=0) {
    flgr2d_destroy(dattmp);
    return ret;
  }

  ret=flgr2d_minkowski_add(datdest,dattmp,nhb);

  flgr2d_destroy(dattmp);

  return ret;
}

////////////////////////////////////////////////////////////////////////////
/*! Closing using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_MorphoOptim flag;
  FLGR_Data2D *dattmp;
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;
  if((ret=flgr2d_is_data_same_type(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("data types differents\n");
    return ret;
  }
  if((ret=flgr2d_is_data_same_spp(datdest,nhb))!=FLGR_RET_OK) {
    POST_ERROR("spp differents\n");
    return ret;
  }


  flag = flgr2d_get_optimization_available(datdest, datsrc, nhb);

  switch(flag) {
  case FLGR_MORPHO_OPTIM_SQUARE:
    return flgr2d_close_square(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_HEXAGON:
    return flgr2d_close_hexa(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_RECTANGLE:
    if(nhb->type != FLGR_BIT)
      return flgr2d_close_rectangle(datdest,datsrc,nhb->size_x,nhb->size_y);
    else
      return flgr2d_close_square(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_OCTAGON:
    return flgr2d_close_octagon(datdest,datsrc,nhb->size_x/2);

  case FLGR_MORPHO_OPTIM_DIAMOND:
    return flgr2d_close_cross(datdest,datsrc,nhb->size_x/2);

  default:
    break;
  }
  

  dattmp = flgr2d_create_pixmap(datsrc->size_y, datsrc->size_x, datdest->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_dilate(dattmp, datsrc, nhb))!=0) {
    flgr2d_destroy(dattmp);
    return ret;
  }

  ret=flgr2d_minkowski_sub(datdest,dattmp,nhb);

  flgr2d_destroy(dattmp);

  return ret;
}

////////////////////////////////////////////////////////////////////////////
/*! Tophat by Openning using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open_tophat(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_open(datdest, datsrc, nhb))!=0) return ret;

  ret=flgr2d_arith_sub(datdest,datsrc,datdest);

  return ret;
}

////////////////////////////////////////////////////////////////////////////
/*! Tophat by Closing using a specific neighborhood definition
 *  @param *datdest : pointer to the image
 *  @param *datsrc : pointer to the image
 *  @param *nhb : pointer the the Neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close_tophat(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL) || (nhb==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_close(datdest,datsrc,nhb))!=0) return ret;

  ret=flgr2d_arith_sub(datdest,datdest,datsrc);

  return ret;
}


//! @}
